#include <stdio.h>      // 标准输入输出
#include "ohos_init.h"  // 用于初始化服务(services)和功能(features)
#include "cmsis_os2.h"  // CMSIS-RTOS API V2

#include "hi_io.h"
#include "hi_gpio.h"

#include "MQTTClient.h" //mqtt三方库
#include "cJSON.h"      //cJson解析三方库

#include "wifi_connecter.h" // easy wifi (station模式)
#include "iot_watchdog.h" 

#define LED_GPIO HI_IO_NAME_GPIO_7
#define KEY_GPIO HI_IO_NAME_GPIO_5


// 定义一个宏，用于标识SSID。请根据实际情况修改
#define PARAM_HOTSPOT_SSID "w"

// 定义一个宏，用于标识密码。请根据实际情况修改
#define PARAM_HOTSPOT_PSK "12345678"

// 定义一个宏，用于标识加密方式
#define PARAM_HOTSPOT_TYPE WIFI_SEC_TYPE_PSK

// 定义一个宏，用于标识MQTT服务器IP地址。请根据实际情况修改
#define HOST_ADDR "59e62b5755.st1.iotda-device.cn-north-4.myhuaweicloud.com"

// 定义一个宏，用于标识MQTT服务器端口
#define HOST_PORT 1883

// 定义一个宏，用于标识智能家居的设备ID
#define DEVICE_ID "67eb96a85367f573f77e8956_led_light_test"
// 定义一个宏，用于标识用于MQTT连接的clientid
#define MQTT_CLIENT_ID "67eb96a85367f573f77e8956_led_light_test_0_0_2025041602"

// 定义一个宏，用于标识用于MQTT连接的username
#define MQTT_USERNAME "67eb96a85367f573f77e8956_led_light_test"

// 定义一个宏，用于标识用于MQTT连接的password
#define MQTT_PASSWORD "c65c1d8887c8435d4d0298cd1504c0f8a7b9de4fbca45c6d479449e03ab4ee04"



// 定义一个宏，用于标识设备属性上报所用的topic
#define PUBLISH_TOPIC "$oc/devices/"DEVICE_ID"/sys/properties/report"
// 定义一个宏，用于标识订阅下发命令所用的topic
#define SUBCRIB_TOPIC "$oc/devices/"DEVICE_ID"/sys/commands/#" 
// 定义一个宏，用于标识执行完成下发命令所返回响应的topic
#define RESPONSE_TOPIC "$oc/devices/"DEVICE_ID"/sys/commands/response" 

//定义用于mqtt连接的两个对象变量，对象类型来自mqtt三方库
Network network;    
MQTTClient client;

static unsigned char sendBuf[1000];
static unsigned char readBuf[1000];


static void mqtt_init(void)
{
    printf(">>>>>>>>>> MQTTDemoTask ...\n");
    // 连接AP
    // 定义热点配置
    WifiDeviceConfig config = {0};
    // 设置热点配置中的SSID
    strcpy(config.ssid, PARAM_HOTSPOT_SSID);
    // 设置热点配置中的密码
    strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);
    // 设置热点配置中的加密方式
    config.securityType = PARAM_HOTSPOT_TYPE;
    // 等待100ms
    osDelay(10);
    // 连接到热点
    int netId = ConnectToHotspot(&config);
  
    // 检查是否成功连接到热点
    if (netId < 0)
    {
        printf("Connect to AP failed!\r\n");
        return;
    }
    printf("wifi connect successful !\n");

    // 初始化并启动MQTT任务，连接MQTT服务器
    int rc = 0;
begin:   
    //初始化NetworkInit
    NetworkInit(&network);
    // 连接网络
    NetworkConnect(&network, HOST_ADDR, HOST_PORT);

    printf("MQTTClientInit  ...\n");

    MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));

    MQTTString clientId = MQTTString_initializer;
    clientId.cstring = MQTT_CLIENT_ID;
    MQTTString userName = MQTTString_initializer;
    userName.cstring = MQTT_USERNAME;
    MQTTString password = MQTTString_initializer;
    password.cstring = MQTT_PASSWORD;
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.clientID = clientId;
    data.username = userName;
	data.password = password;
    data.willFlag = 0;
    data.MQTTVersion = 4;
    data.keepAliveInterval = 60;
    data.cleansession = 1;
    printf("MQTTConnect  ...\n");
    
    rc = MQTTConnect(&client, &data);
    if (rc != 0) {
        printf("MQTTConnect: %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        goto begin;
    }else{
        printf("MQTTConnect successful \n");
    }
}

// mqtt发送
void mqtt_publish(hi_gpio_value led_val)
{
    MQTTMessage message;
    char payload[500]={0};
    
    //--将读取到的AHT20传感器数据封装成上华为云iot平台的数据结构--start
    cJSON *root = cJSON_CreateObject(); // 创建JSON对象

    if (root != NULL) {
        // 创建数组，用于存放服务数据
        cJSON *serv_arr = cJSON_AddArrayToObject(root, "services");

        // 创建数组项，代表单个服务
        cJSON *arr_item = cJSON_CreateObject();

        // 添加服务ID
        cJSON_AddStringToObject(arr_item, "service_id", "service_iot_led");

        // 创建对象，用于存放属性
        cJSON *pro_obj = cJSON_CreateObject();
        cJSON_AddItemToObject(arr_item, "properties", pro_obj);

        // 添加温度和湿度数据到属性对象
        if(led_val == HI_GPIO_VALUE1){
            cJSON_AddStringToObject(pro_obj, "light", "OFF");
        }else{
            cJSON_AddStringToObject(pro_obj, "light", "ON");
        }

        // 将服务数组项添加到服务数组中
        cJSON_AddItemToArray(serv_arr, arr_item);

        // 将JSON对象转换为字符串
        char *payload_str = cJSON_PrintUnformatted(root);
        if (payload_str != NULL) {
            strcpy(payload, payload_str); // 将JSON字符串复制到payload
            cJSON_free(payload_str); // 释放cJSON分配的内存
        }

        // 删除JSON对象，释放内存
        cJSON_Delete(root);
    }
    
    message.qos = 0;
    message.retained = 0;
    message.payload = payload;
    
    message.payloadlen = strlen(payload);

    int rc = 0;

    if ((rc = MQTTPublish(&client, PUBLISH_TOPIC, &message)) != 0) {
        printf("Return code from MQTT publish is %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        mqtt_init();
    }else{
        printf("mqtt publish success:%s\n",payload);
    }
}

// 安装中断处理函数
void keyPressedFunc(void *arg)
{
    /*
        静态局部变量：
        使用 static 声明的局部变量在程序运行期间一直存在（即它的生命周期是整个程序运行期间），但它仍然只能在声明它的函数内部访问（即作用域不变）。
        此外，静态局部变量只会被初始化一次，之后的函数调用会保留上次的值。
    */ 
    static hi_gpio_value led_val = HI_GPIO_VALUE0;
    (void)arg;
    printf("key pressed \n");
    printf("led_val %d \n",led_val);
    // 设置LED的电平
    hi_gpio_set_ouput_val(LED_GPIO,led_val);
    mqtt_publish(led_val);
    led_val = !led_val;
    return ;
}

void led_init(void)
{
    // 初始化GPIO
    // hi_io.h 包中的接口
    hi_gpio_init();

    // 设置gpio下拉模式 (默认低电平灭)
    hi_io_set_pull(LED_GPIO,HI_IO_PULL_NONE);

    // 设置io引脚为通用IO (因为芯片引脚少 功能多 所以先设置该引脚是干什么作用的)
    hi_io_set_func(LED_GPIO,HI_IO_FUNC_GPIO_7_GPIO);

    // 设置GPIO为输出
    hi_gpio_set_dir(LED_GPIO,HI_GPIO_DIR_OUT);
    hi_gpio_set_ouput_val(LED_GPIO,HI_GPIO_VALUE1);
    return ;
}

void key_init(void)
{
    // 初始化GPIO
    hi_gpio_init();

    // 设置io引脚为通用IO (因为芯片引脚少 功能多 所以先设置该引脚是干什么作用的)
    hi_io_set_func(KEY_GPIO,HI_IO_FUNC_GPIO_5_GPIO);

    // 设置gpio上拉（默认高电平）
    // hi_io_set_pull(KEY_GPIO,HI_IO_PULL_UP);

    // 设置GPIO为输入
    hi_gpio_set_dir(KEY_GPIO,HI_GPIO_DIR_IN);

    // 注册GPIO中断处理函数
    hi_gpio_register_isr_function(KEY_GPIO,   /* GPIO引脚 */
        HI_INT_TYPE_EDGE,                     /* 边沿触发 */
        HI_GPIO_EDGE_FALL_LEVEL_LOW,          /* 下降沿触发 */
        keyPressedFunc,                       /* 中断处理函数 */
        NULL
    );

    return;
}

static void mqtt_led_task(void)
{
    mqtt_init();
    led_init();
    key_init();
}

static void led_switch(void)
{
    IoTWatchDogDisable();
    osThreadAttr_t attr;               // 定义一个线程属性

    attr.name = "LedTask";             // 设置任务名
    attr.stack_size = 10240;            // 设置线程任务栈空间大小
    attr.priority = osPriorityNormal;  // 设置线程优先级

    // 创建线程（到内核API详述）
    // 1.0 CMSIS-RTOS2 API：third_party\cmsis\CMSIS\RTOS2\Include\cmsis_os2.h
    // 1.1.3 kernel\liteos_m\kal\cmsis\cmsis_liteos2.c
    // RTOS: real-time operating system
    // CMSIS: Cortex Microcontroller Software Interface Standard
    if (osThreadNew((osThreadFunc_t)mqtt_led_task, NULL, &attr) == NULL)
    {
        printf("[led_switch] Create mqtt_led_task failed!\n");
    }
}

// ohos_init.h 中定义的宏，让函数在系统启动时执行
// SYS_RUN(led_switch);
APP_FEATURE_INIT(led_switch);
